package com.oreilly.ez.web;

import cn.afterturn.easypoi.excel.ExcelExportUtil;
import cn.afterturn.easypoi.excel.entity.TemplateExportParams;
import com.oreilly.ez.base.R;
import com.oreilly.ez.base.SysNote;
import com.oreilly.ez.base.YmlConfig;
import com.oreilly.ez.entity.FileItem;
import com.oreilly.ez.repo.FileItemRepo;
import com.oreilly.ez.util.DateTool;
import com.oreilly.ez.vo.DayNote;
import org.apache.commons.io.IOUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.util.Assert;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.math.BigDecimal;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@RestController
@Validated
@RequestMapping("/file-items")
public class FileItemCtrl extends BaseCtrl<FileItem> {


    @Autowired
    private YmlConfig ymlConfig;

    @Autowired
    private FileItemRepo fileItemRepo;



    @Override
    public Object find(FileItem fileItem, Pageable pageable) {

//        if(fileItem == null) fileItem = new FileItem();
//        Page<FileItem> fileItemPage = fileItemRepo.findAll(Example.of(fileItem), pageable);

        Specification<FileItem> specification =  (root, criteriaQuery, criteriaBuilder) -> {

            List<Predicate> predicateList = new ArrayList<>();
            String fileName = fileItem.getFileName();
            if(org.apache.commons.lang3.StringUtils.isNotBlank(fileName)){
                Predicate predicate = criteriaBuilder.like(root.get("fileName").as(String.class), "%" + fileName + "%");
                predicateList.add(predicate);
            }


//            return criteriaQuery.where(predicateList.toArray(new Predicate[predicateList.size()])).getRestriction();
            return criteriaBuilder.and(predicateList.toArray(new Predicate[predicateList.size()]));
        };

        Page<FileItem> page = fileItemRepo.findAll(specification, pageable);
//        return R.ok(fileItemPage);
        return R.ok(page);
    }

    @Override
    public Object findOne(@PathVariable Integer id) {
        return fileItemRepo.findById(id);
    }

    @Override
    public Object save(@Valid FileItem fileItem) {
        return null;
    }

    @Override
    public Object delete(@PathVariable Integer id) {

        fileItemRepo.deleteById(id);
        return R.ok("delete success");
    }


    /**
     * 文件上传
     * @param file
     * @return
     * @throws IOException
     */
    @SysNote(name = "上传文件")
    @PostMapping("/upload")
    @ResponseBody
    public Object onUpload(MultipartFile file) throws IOException {


        if (file.isEmpty()) {
            return R.err("file is empty");
        }

        String filename = file.getOriginalFilename();

        //文件大小, 6 M
        double size = file.getSize()/1024.0D/1024;


//        ApplicationHome home = new ApplicationHome(getClass());
//        File jarFile = home.getSource();
//        File parentFile = jarFile.getParentFile();

//        File dir = new File(parentFile, ymlConfig.getUploadDir());
//        FileSystemResource dir = new FileSystemResource(ymlConfig.getUploadDir());
//        String path = dir.getPath();
//        System.out.println(path);

        File dir = new File(System.getProperty("user.dir"), ymlConfig.getUploadDir());

        //DefaultResourceLoader, get 项目路径下的文件夹
//        DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
//        Resource resource = resourceLoader.getResource(ymlConfig.getUploadDir());
//        File dir = resource.getFile();
        String fileExt = getFileExt(filename);
        File tempFile = File.createTempFile("file", fileExt, dir);

        try (InputStream in = file.getInputStream();
             FileOutputStream out = new FileOutputStream(tempFile)) {
            IOUtils.copy(in, out);
        }


        //save to db
        FileItem fileItem = new FileItem();
        fileItem.setUdate(new Date());
        fileItem.setFileName(filename);
        fileItem.setExt(fileExt);
        fileItem.setSize(size);
        fileItem.setUploadName(tempFile.getName());

        fileItemRepo.save(fileItem);

        return R.ok(fileItem);


    }





    private String getFileExt(String filename) {

        return filename.substring(filename.lastIndexOf("."));
    }


    /**
     * 判断上传的file, 是否图片??
     * @param file
     * @return
     */
    private boolean isImage(MultipartFile file){
        return  file.getContentType().startsWith("image");
    }


    /**
     * file:./uploads/ 映射成静态路径后, 直接访问即可
     * http://127.0.0.1:9300/file5727312880157182115.zip
     * 但是下载的名字, 如果要远离的文件名(协议书.zip), 需要使用这个方法
     *
     * @param uploadName
     * @param response
     * @throws IOException
     */
    @RequestMapping("/download/{uploadName}")
    public void download(@PathVariable String uploadName, HttpServletRequest request, HttpServletResponse response) throws IOException {

        response.reset();
        FileItem dbFileItem = fileItemRepo.findFileItemByUploadName(uploadName);
        String fileName = dbFileItem.getFileName();
        response.setHeader("Content-Type", URLConnection.guessContentTypeFromName(fileName));
        //支持中文
//        fileName = URLEncoder.encode(fileName,"UTF-8");


        String userAgent = request.getHeader("User-Agent");
        byte[] bytes = userAgent.contains("MSIE")? fileName.getBytes(): fileName.getBytes("UTF-8");
        String downloadFileName = new String(bytes, "ISO-8859-1");
        response.setHeader("Content-Disposition", "attachment;filename="+downloadFileName);


//
//        DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
//        Resource resource = resourceLoader.getResource(ymlConfig.getUploadDir());
//        File dir = resource.getFile();

        File dir = new File(System.getProperty("user.dir"), ymlConfig.getUploadDir());
        File file = new File(dir, uploadName);

        InputStream in = new FileInputStream(file);
        IOUtils.copy(in, response.getOutputStream());

    }






    /**
     *
     *
     * excel 每月工单表, 模板, 导出
     *
     *
     * 一月 Jan. January
     * <p>
     * 二月 Feb. February
     * <p>
     * 三月 Mar. March
     * <p>
     * 四月 Apr. April
     * <p>
     * 五月 May. May
     * <p>
     * 六月 Jun. June
     * <p>
     * 七月 Jul. July
     * <p>
     * 八月 Aug. August
     * <p>
     * 九月 Sept. September
     * <p>
     * 十月 Oct. October
     * <p>
     * 十一月 Nov. November
     * <p>
     * 十二月 Dec. December
     *
     * @param request
     * @param res
     * @param year
     * @param month
     * @throws IOException
     */
    @RequestMapping(value = "/time-card/{year}/{month}")
    public void timeCard(HttpServletRequest request, HttpServletResponse res, @PathVariable Integer year, @PathVariable Integer month) throws IOException {

        Assert.notNull(year, "year is null");
        Assert.notNull(month, "month is null");

        String[] monthAbbr = {"", "Jan.", "Feb.", "Mar.", "Apr.", "May.", "Jun.", "Jul.", "Aug.", "Sept.", "Oct.", "Nov.", "Dec.",};


        String fileName = "Timecard-" + year + "-" + month + ".xlsx";
        res.setHeader("Content-Disposition", "attachment; filename=" + java.net.URLEncoder.encode(fileName, "UTF-8"));


        List<String> dayList = DateTool.dayList(year, month);


        int lastDay = dayList.size();
        String period = String.format("%s %s %s -%s %s %s", monthAbbr[month], 1, year, monthAbbr[month], lastDay, year);

        List<DayNote> dayNoteList = dayList.stream().map(ele -> {

            DayNote dayNote = new DayNote();
            DateTime dateTime = new DateTime(ele);

            Date logDate = dateTime.toDate();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(logDate);

            dayNote.setLogDate(logDate);
            dayNote.setNote("");

            if (calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY ||
                    calendar.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY) {
                dayNote.setNote("Weekend");
            }

            return dayNote;
        }).collect(Collectors.toList());


        for (DayNote dayNote : dayNoteList) {

            Date logDate = dayNote.getLogDate();
            String date = new DateTime(logDate).toString("MM/dd/yyyy");
            dayNote.setDate(date);
        }


        //Total row

        DayNote total = new DayNote();
        total.setDate("Total");
        total.setTime1("");
        total.setTime2("");
        total.setRegularHours(BigDecimal.ZERO);

        dayNoteList.add(total);


        // 获取导出excel指定模版
        File templateFile = ResourceUtils.getFile("conf/Timecard.xlsx");
//        File templateFile = new File(ymlConfig.getTemplatePath(), "Timecard.xlsx");
        TemplateExportParams params = new TemplateExportParams(templateFile.getAbsolutePath());
//        params.setTemplateUrl(templateFile.getAbsolutePath());
        params.setTempParams("t");
        Map<String, Object> data = new HashMap<>();
        data.put("list", dayNoteList);
        data.put("period", period);

//        ExportParams params = new ExportParams("课程详情", null, "课程详情");
//        Workbook workbook = ExcelExportUtil.exportExcel(params, data);
        Workbook workbook = ExcelExportUtil.exportExcel(params, data);

        // 数字格式
        Sheet sheet = workbook.getSheetAt(0);
        int rows = sheet.getPhysicalNumberOfRows();
        System.out.println(String.format("total rows = %s", rows));


        for (int i = 8; i < rows; i++) {

            Row row = sheet.getRow(i);
            Cell cell = row.getCell(6);
            cell.setCellType(CellType.NUMERIC);
            cell.setCellValue(8);



            //背景色
            Cell bgCell = row.getCell(3);
            String stringCellValue = bgCell.getStringCellValue();
            if("Weekend".equals(stringCellValue)){

                cell.setCellValue(0);

                //周末
                int totalCells = row.getPhysicalNumberOfCells();
                for (int j = 0; j < totalCells; j++) {

                    Cell tempCell = row.getCell(j);
                    CellStyle tempCellCellStyle = tempCell.getCellStyle();

                    CellStyle cellStyle = workbook.createCellStyle();
                    cellStyle.cloneStyleFrom(tempCellCellStyle);
                    cellStyle.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
                    cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                    tempCell.setCellStyle(cellStyle);
                }


            }
        }


        workbook.write(res.getOutputStream());
    }


    /**
     * 生成 空文件
     * random/5  生成 5M 大小的文件
     * @param size
     * @return
     * @throws IOException
     */
    @GetMapping("/random/{size}")
    public Object random(@PathVariable long size) throws IOException {

        Assert.notNull(size, "文件大小不能为空");
        long length = size * 1024 * 1024;

        File dir = new File(System.getProperty("user.dir"), ymlConfig.getUploadDir());

        File file = new File(dir, "rand-" + DateTime.now().toString("yyyy-MM-dd-HH-mm-ss") + ".txt");

        RandomAccessFile r = null;
        try {
            r = new RandomAccessFile(file, "rw");
            r.setLength(length);
        }   finally{
            if (r != null) {
                try {
                    r.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        //save to db
        FileItem fileItem = new FileItem();
        fileItem.setUdate(new Date());
        String fname = file.getName();
        fileItem.setFileName(fname);
        fileItem.setExt(".txt");
        fileItem.setSize(Double.valueOf(size));
        fileItem.setUploadName(fname);

        fileItemRepo.save(fileItem);

        return R.ok(fileItem);

    }
}
